package com.example.wifidirect

import android.Manifest
import android.annotation.SuppressLint
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.content.pm.PackageManager
import android.net.wifi.p2p.WifiP2pConfig
import android.net.wifi.p2p.WifiP2pDevice
import android.net.wifi.p2p.WifiP2pInfo
import android.net.wifi.p2p.WifiP2pManager
import android.net.wifi.p2p.nsd.WifiP2pDnsSdServiceInfo
import android.net.wifi.p2p.nsd.WifiP2pDnsSdServiceRequest
import android.os.Build
import android.os.Bundle
import android.util.Log
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.activity.result.contract.ActivityResultContracts
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Button
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import com.example.wifidirect.net.Client
import com.example.wifidirect.net.Server
import com.example.wifidirect.ui.theme.WiFiDirectTheme
import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch

class MainActivity : ComponentActivity() {
    private val manager: WifiP2pManager by lazy(LazyThreadSafetyMode.NONE) {
        getSystemService(Context.WIFI_P2P_SERVICE) as WifiP2pManager
    }

//    private val connectivityManager: ConnectivityManager by lazy(LazyThreadSafetyMode.NONE) {
//        getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
//    }

    var channel: WifiP2pManager.Channel? = null
    var receiver: BroadcastReceiver? = null

    private val server: Server by lazy {
        Server()
    }

    private val client: Client by lazy {
        Client()
    }

    private var discoveryJob: Job? = null

    private val serviceInstanceName = "ultrasound_ranging"

    //  Create a string map containing information about your service.
    val record: Map<String, String> = mapOf(
        "listenport" to 8888.toString(),
        "buddyname" to "John Doe${(Math.random() * 1000).toInt()}",
        "available" to "visible"
    )

    // Service information.  Pass it an instance name, service type
    // _protocol._transportlayer , and the map containing
    // information other devices will want once they connect to this one.
    val serviceInfo =
        WifiP2pDnsSdServiceInfo.newInstance(serviceInstanceName, "_presence._tcp", record)


//    private val networkCallback = object : ConnectivityManager.NetworkCallback() {
//        override fun onAvailable(network: Network) {
//            super.onAvailable(network)
//            // 当网络可用时的处理逻辑
//            Log.d("networkCallback", "Network is available")
//        }
//
//        override fun onLost(network: Network) {
//            super.onLost(network)
//            // 当网络丢失时的处理逻辑
//            Log.d("networkCallback", "Network is lost")
//        }
//
//        override fun onCapabilitiesChanged(
//            network: Network,
//            networkCapabilities: NetworkCapabilities
//        ) {
//            super.onCapabilitiesChanged(network, networkCapabilities)
//            // 当网络能力发生变化时的处理逻辑
//            if (networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_WIFI_P2P)) {
//                Log.d("networkCallback", "Network has internet capability")
//            }
//        }
//    }

    private val wifiP2pReceiver = object : BroadcastReceiver() {
        @SuppressLint("MissingPermission", "NewApi")
        override fun onReceive(context: Context, intent: Intent) {
            val action = intent.action
            when (action) {
                WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION -> {   // 当 WLAN P2P 在设备上启用或停用时广播。
                    val state = intent.getIntExtra(WifiP2pManager.EXTRA_WIFI_STATE, -1)
//                    isWifiP2pEnabled = (state == WifiP2pManager.WIFI_P2P_STATE_ENABLED)
                    Log.d("STATE_CHANGED", "$state")
                    if (state == WifiP2pManager.WIFI_P2P_STATE_ENABLED) {
                        addDiscoverServiceRequest()
                        startDiscovery()
                    } else {
                        cancelDiscovery()
                    }
                }
                // 在调用 discoverPeers() 时广播。如果您在应用中处理此 intent，则通常需要调用 requestPeers() 以获取对等设备的更新列表。
                WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION -> {
                    Log.d("PEERS_CHANGED", "")
//                    manager.requestPeers(channel) { peerList ->
//                        val deviceList = peerList.deviceList
//                        Log.d("WifiP2pDeviceList", "$deviceList")
//                        for (device in deviceList) {
//                            if (device.isGroupOwner) {
//                                // 找到群组所有者，尝试连接
////                                    connectToGroup(device)
//                                Log.d("GroupOwner", "group owner: ${device.deviceName}")
//                                manager.requestGroupInfo(channel) { it: WifiP2pGroup? ->
//                                    Log.d("WifiP2pGroup", "${it?.owner}")
//                                }
//
//                            }
//                        }
//                    }
                }

                WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION -> {  // 当设备的 WLAN 连接状态更改时广播
                    // 处理连接变化
                    Log.d("CONNECTION_STATE_CHANGE", "")

                    manager.requestConnectionInfo(channel) {
                        Log.d("WiFiP2P", "is groupFormed: ${it.groupFormed}")
                        //                    text.value = "groupFormed=${it.groupFormed}, isGroupOwner=${it.isGroupOwner}"
                        if (it.groupFormed) {
                            val isGroupOwner = it.isGroupOwner
                            val addr = it.groupOwnerAddress
                            Log.d("is Group Owner?", "$isGroupOwner")
                            Log.d("address of GO?", "$addr")

                            if(isGroupOwner) {

                            } else {
                                //                            if (!client.isClientSocketRunning()) {
                                //                                it.groupOwnerAddress.hostAddress?.let { it1 -> client.startClient(it1) }
                                //                            }
                                //                            client.write("Ping")
                            }
                        }

                    }


                    manager.requestConnectionInfo(channel) { it: WifiP2pInfo ->
                        if(it.groupFormed) {
                            if (it.isGroupOwner) {

                            } else {
//                                it.groupOwnerAddress
                            }
                        }
                    }


//                    manager.requestGroupInfo(channel) { it: WifiP2pGroup? ->
////                        Log.d("WifiP2pGroup", "${it.owner}")
//                    }

                }

                WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION -> { // 当设备的详细信息（例如设备名称）更改时广播。
                    // 处理本设备信息变化
                    Log.d("THIS_DEVICE_CHANGED", "")
                }
            }
        }
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        // Registers the application with the Wi-Fi framework.
        channel = manager.initialize(this, mainLooper) {
            Log.d("onChannelDisconnected", "The channel to the framework has been disconnected.")
        }

//        // 创建 NetworkRequest 对象
//        val networkRequest = NetworkRequest.Builder()
//            .addCapability(NetworkCapabilities.NET_CAPABILITY_WIFI_P2P)
//            .build()
//
//        // 注册 NetworkCallback
//        connectivityManager.registerNetworkCallback(networkRequest, networkCallback)

        checkPermissions()



//        // 应用启动时同时启动服务发现
//        startDiscovery()

        enableEdgeToEdge()
        setContent {
            WiFiDirectTheme {
                Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding ->
                    Column {
                        Greeting(
                            name = "Android",
                            modifier = Modifier.padding(innerPadding)
                        )
                        Button(onClick = { startRanging() }) {
                            Text("开始测距")
                        }
                        Button(onClick = { addLocalService() }) {
                            Text("addLocalService")
                        }

                        Text("添加服务👇")
                        Row {
                            Button(onClick = { addLocalService() }) {
                                Text("addLocalService")
                            }
                            Button(onClick = { removeLocalService() }) {
                                Text("removeLocalService")
                            }
                        }

                        Text("发现服务👇")
                        Row {
                            Button(onClick = { startDiscovery() }) {
                                Text("startDiscovery")
                            }
                            Button(onClick = { cancelDiscovery() }) {
                                Text("cancelDiscovery")
                            }
                        }

                        Text("服务器：建立网络连接👇")
                        Row {
                            Button(onClick = { server.startServer() }) {
                                Text("startServer")
                            }
                            Button(onClick = { server.cancelServer() }) {
                                Text("cancelServer")
                            }
                        }

                        Text("客户端：建立网络连接👇")
                        Row {
                            Button(onClick = { client.startClient("") }) {
                                Text("startClient")
                            }
                            Button(onClick = { client.cancelClient() }) {
                                Text("cancelClient")
                            }
                        }

                    }

                }
            }
        }
    }

    /* register the broadcast receiver with the intent values to be matched */
    override fun onResume() {
        super.onResume()

        val intentFilter = IntentFilter().apply {
            addAction(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION)
            addAction(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION)
            addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION)
            addAction(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION)
        }
        registerReceiver(wifiP2pReceiver, intentFilter)
        Log.d("registerReceiver", "")
    }

    /* unregister the broadcast receiver */
    override fun onPause() {
        super.onPause()
        unregisterReceiver(wifiP2pReceiver)
    }

    private fun checkPermissions() {
        val permissionP2P = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
            Manifest.permission.NEARBY_WIFI_DEVICES     // Android 13+ 需要NEARBY_WIFI_DEVICES权限
        } else {
            Manifest.permission.ACCESS_FINE_LOCATION    // Android <=12 需要ACCESS_FINE_LOCATION权限
        }

        when {
            ContextCompat.checkSelfPermission(
                this, permissionP2P
            ) == PackageManager.PERMISSION_GRANTED -> {
//                discoverPeers()
            }

            ActivityCompat.shouldShowRequestPermissionRationale(
                this, permissionP2P
            ) -> {
                // In an educational UI, explain to the user why your app requires this
                // permission for a specific feature to behave as expected, and what
                // features are disabled if it's declined. In this UI, include a
                // "cancel" or "no thanks" button that lets the user continue
                // using your app without granting the permission.
//                    showInContextUI(...)
                // TODO: 第一次被拒，二次权限申请？
            }

            else -> {
                // You can directly ask for the permission.
                // The registered ActivityResultCallback gets the result of this request.
                val requestPermissionLauncher = registerForActivityResult(
                    ActivityResultContracts.RequestPermission()
                ) { isGranted: Boolean ->
                    if (isGranted) {
//                        discoverPeers()
                    } else {
                        // 权限被拒绝
                        Log.d("RequestPermission", "Permission rejected.")
                    }
                }
                requestPermissionLauncher.launch(permissionP2P)
            }
        }
    }

    @SuppressLint("MissingPermission")
    private fun addLocalService() {
        val serviceInfo =
            WifiP2pDnsSdServiceInfo.newInstance(serviceInstanceName, "_presence._tcp", record)
        manager.addLocalService(channel, serviceInfo, object : WifiP2pManager.ActionListener {
            override fun onSuccess() {
                Log.d("addLocalService", "success")
            }

            override fun onFailure(reason: Int) {
                Log.e("addLocalService", "failed: $reason")
            }
        })
    }

    private fun removeLocalService() {
        manager.removeLocalService(channel, serviceInfo, object : WifiP2pManager.ActionListener {
            override fun onSuccess() {
                // Command successful! Code isn't necessarily needed here,
                // Unless you want to update the UI or add logging statements.
                Log.d("removeLocalService", "success")
            }

            override fun onFailure(reason: Int) {
                // Command failed.  Check for P2P_UNSUPPORTED, ERROR, or BUSY
                Log.e("removeLocalService", "failed: $reason")
            }
        })
    }

    private val buddies = mutableMapOf<String, String>()


    // 添加发现服务请求和回调
    // TODO: 移动相关代码到合适的地方
    private fun addDiscoverServiceRequest() {
        /* Callback includes:
         * fullDomain: full domain name: e.g. "printer._ipp._tcp.local."
         * record: TXT record dta as a map of key/value pairs.
         * device: The device running the advertised service.
         */
        val txtListener = WifiP2pManager.DnsSdTxtRecordListener { fullDomainName, txtRecordMap, srcDevice ->
            Log.d("DnsSdTxtRecord", "DnsSdTxtRecord available - $fullDomainName, $txtRecordMap, $srcDevice")
//            txtRecordMap["buddyname"]?.also {
//                buddies[srcDevice.deviceAddress] = it
//            }
        }

        val servListener =
            WifiP2pManager.DnsSdServiceResponseListener { instanceName, registrationType, srcDevice ->
                // Update the device name with the human-friendly version from
                // the DnsTxtRecord, assuming one arrived.
//                srcDevice.deviceName =
//                    buddies[srcDevice.deviceAddress] ?: srcDevice.deviceName

                Log.d("DnsSdService", "发现服务实例: $instanceName, 类型: $registrationType, 设备: ${srcDevice.deviceName}")
                if (instanceName == serviceInstanceName) {
                    connectToDevice(srcDevice)  // connect
                }
            }

        manager.setDnsSdResponseListeners(channel, servListener, txtListener)

        val serviceRequest = WifiP2pDnsSdServiceRequest.newInstance()
        manager.addServiceRequest(
            channel,
            serviceRequest,
            object : WifiP2pManager.ActionListener {
                override fun onSuccess() {
                    Log.d("addServiceRequest", "ok")
                }

                override fun onFailure(code: Int) {
                    Log.d("addServiceRequest", "error: $code")
                }
            }
        )
    }

    // 启动发现服务协程，第一次运行之前需要先add Service Request
    // TODO: 移动相关代码到合适的地方
    private fun startDiscovery() {
        if (discoveryJob?.isActive == true) {
            Log.d("DiscoveryJob", "already in active state")
            return
        }
        discoveryJob = startDiscoveryJob(10 * 1000)
    }

    // TODO: 移动相关代码到合适的地方
    private fun cancelDiscovery() {
        Log.d("DiscoveryJob", "try cancelDiscovery")
        discoveryJob?.cancel()
        discoveryJob = null
    }

    // TODO: 移动相关代码到合适的地方
    @SuppressLint("MissingPermission")
    fun startDiscoveryJob(delayMillis: Long) = CoroutineScope(Dispatchers.Main).launch {
        Log.d("startDiscoveryJob", " DiscoveryJob running, repeat: ${delayMillis / 1000.0}s")
        while (coroutineContext.isActive) {
            Log.d("DiscoveryJob", "try discoverService")
            manager.discoverServices(
                channel,
                object : WifiP2pManager.ActionListener {
                    override fun onSuccess() {
                        // Success!
                    }

                    override fun onFailure(code: Int) {
                        // Command failed. Check for P2P_UNSUPPORTED, ERROR, or BUSY
                        when (code) {
                            WifiP2pManager.P2P_UNSUPPORTED -> {
                                Log.d("DiscoveryJob", "Wi-Fi Direct isn't supported on this device.")
                            }
                        }
                    }
                }
            )
            try {
                delay(delayMillis)  // 在等待期间如果协程被取消，则会抛出错误
            } catch (_: CancellationException) {

            }

        }
        Log.d("DiscoveryJob", "DiscoveryJob was cancelled")
    }



    @SuppressLint("MissingPermission")
    private fun connectToDevice(device: WifiP2pDevice) {
        val config = WifiP2pConfig()
        config.deviceAddress = device.deviceAddress

        manager.connect(channel, config, object : WifiP2pManager.ActionListener {
            override fun onSuccess() {
                Log.d("connectToDevice", "ok")
            }

            override fun onFailure(code: Int) {
                Log.e("connectToDevice", "code: $code")
            }
        })
    }

    fun cancelConnect() {
        manager.cancelConnect(channel, object : WifiP2pManager.ActionListener {
            override fun onSuccess() {
                Log.d("cancelConnect", "ok")
            }

            override fun onFailure(reason: Int) {
                Log.e("cancelConnect", "code: $reason")
            }
        })
    }


    @SuppressLint("MissingPermission")
    fun discoverPeers() {
        // 使用协程定期搜索
        CoroutineScope(Dispatchers.Main).launch {
            while (isActive) {
                Log.d("discoverPeers", "try discoverPeers")
                manager.discoverPeers(channel, object : WifiP2pManager.ActionListener {
                    override fun onSuccess() {
                        Log.d("discoverPeers", "success")
                    }

                    override fun onFailure(reasonCode: Int) {
                        Log.d("discoverPeers", "failure, code: $reasonCode")
                    }
                })
//                discoverService()
                delay(10 * 1000)
            }
        }
    }

    @SuppressLint("MissingPermission")
    fun createGroup() {
        manager.createGroup(channel, object : WifiP2pManager.ActionListener {
            override fun onSuccess() {
                Log.d("createGroup", "ok")
            }

            override fun onFailure(reason: Int) {
                Log.e("createGroup", "code: $reason")
            }
        })
    }



    fun removeGroup() {
        manager.removeGroup(channel, object : WifiP2pManager.ActionListener {
            override fun onSuccess() {
                Log.d("removeGroup", "success")
            }

            override fun onFailure(reason: Int) {
                Log.e("removeGroup", "failure, code: $reason")
            }
        })
    }

    // TODO
    private fun startRanging() {
        addLocalService()
        createGroup()
//        startServer()



    }


}

@Composable
fun Greeting(name: String, modifier: Modifier = Modifier) {
    Text(
        text = "Hello $name!",
        modifier = modifier
    )
}

@Preview(showBackground = true)
@Composable
fun GreetingPreview() {
    WiFiDirectTheme {
        Greeting("Android")
    }
}